<!DOCTYPE HTML>
<html lang="zh-CN">


<head>
    <meta charset="utf-8">
    <meta name="keywords" content="Android view的绘制流程, Java,Android,前端,后台,全栈,移动端,图形图像">
    <meta name="description" content="">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta name="renderer" content="webkit|ie-stand|ie-comp">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <!-- Global site tag (gtag.js) - Google Analytics -->


    <title>Android view的绘制流程 | 穿破鞋</title>
    <link rel="icon" type="image/png" href="/favicon.png">

    <link rel="stylesheet" type="text/css" href="/libs/awesome/css/all.css">
    <link rel="stylesheet" type="text/css" href="/libs/materialize/materialize.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/aos/aos.css">
    <link rel="stylesheet" type="text/css" href="/libs/animate/animate.min.css">
    <link rel="stylesheet" type="text/css" href="/libs/lightGallery/css/lightgallery.min.css">
    <link rel="stylesheet" type="text/css" href="/css/matery.css">
    <link rel="stylesheet" type="text/css" href="/css/my.css">

    <script src="/libs/jquery/jquery.min.js"></script>

<meta name="generator" content="Hexo 4.2.1"><link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head>


<body>
    <header class="navbar-fixed">
    <nav id="headNav" class="bg-color nav-transparent">
        <div id="navContainer" class="nav-wrapper container">
            <div class="brand-logo">
                <a href="/" class="waves-effect waves-light">
                    
                    <img src="/medias/logo.png" class="logo-img" alt="LOGO">
                    
                    <span class="logo-span">穿破鞋</span>
                </a>
            </div>
            

<a href="#" data-target="mobile-nav" class="sidenav-trigger button-collapse"><i class="fas fa-bars"></i></a>
<ul class="right nav-menu">
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/" class="waves-effect waves-light">
      
      <i class="fas fa-home" style="zoom: 0.6;"></i>
      
      <span>首页</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/categories" class="waves-effect waves-light">
      
      <i class="fas fa-bookmark" style="zoom: 0.6;"></i>
      
      <span>分类</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/tags" class="waves-effect waves-light">
      
      <i class="fas fa-tags" style="zoom: 0.6;"></i>
      
      <span>标签</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/archives" class="waves-effect waves-light">
      
      <i class="fas fa-archive" style="zoom: 0.6;"></i>
      
      <span>归档</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/about" class="waves-effect waves-light">
      
      <i class="fas fa-user-circle" style="zoom: 0.6;"></i>
      
      <span>关于</span>
    </a>
    
  </li>
  
  <li class="hide-on-med-and-down nav-item">
    
    <a href="/friends" class="waves-effect waves-light">
      
      <i class="fas fa-address-book" style="zoom: 0.6;"></i>
      
      <span>友情链接</span>
    </a>
    
  </li>
  
  <li>
    <a href="#searchModal" class="modal-trigger waves-effect waves-light">
      <i id="searchIcon" class="fas fa-search" title="搜索" style="zoom: 0.85;"></i>
    </a>
  </li>
</ul>


<div id="mobile-nav" class="side-nav sidenav">

    <div class="mobile-head bg-color">
        
        <img src="/medias/logo.png" class="logo-img circle responsive-img">
        
        <div class="logo-name">穿破鞋</div>
        <div class="logo-desc">
            
            Never really desperate, only the lost of the soul.
            
        </div>
    </div>

    

    <ul class="menu-list mobile-menu-list">
        
        <li class="m-nav-item">
	  
		<a href="/" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-home"></i>
			
			首页
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/categories" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-bookmark"></i>
			
			分类
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/tags" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-tags"></i>
			
			标签
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/archives" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-archive"></i>
			
			归档
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/about" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-user-circle"></i>
			
			关于
		</a>
          
        </li>
        
        <li class="m-nav-item">
	  
		<a href="/friends" class="waves-effect waves-light">
			
			    <i class="fa-fw fas fa-address-book"></i>
			
			友情链接
		</a>
          
        </li>
        
        
        <li><div class="divider"></div></li>
        <li>
            <a href="https://github.com/chuanpoxie/chuanpoxie.github.io" class="waves-effect waves-light" target="_blank">
                <i class="fab fa-github-square fa-fw"></i>Fork Me
            </a>
        </li>
        
    </ul>
</div>


        </div>

        
            <style>
    .nav-transparent .github-corner {
        display: none !important;
    }

    .github-corner {
        position: absolute;
        z-index: 10;
        top: 0;
        right: 0;
        border: 0;
        transform: scale(1.1);
    }

    .github-corner svg {
        color: #0f9d58;
        fill: #fff;
        height: 64px;
        width: 64px;
    }

    .github-corner:hover .octo-arm {
        animation: a 0.56s ease-in-out;
    }

    .github-corner .octo-arm {
        animation: none;
    }

    @keyframes a {
        0%,
        to {
            transform: rotate(0);
        }
        20%,
        60% {
            transform: rotate(-25deg);
        }
        40%,
        80% {
            transform: rotate(10deg);
        }
    }
</style>

<a href="https://github.com/chuanpoxie/chuanpoxie.github.io" class="github-corner tooltipped hide-on-med-and-down" target="_blank"
   data-tooltip="Fork Me" data-position="left" data-delay="50">
    <svg viewBox="0 0 250 250" aria-hidden="true">
        <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
        <path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
              fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path>
        <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
              fill="currentColor" class="octo-body"></path>
    </svg>
</a>
        
    </nav>

</header>

    



<div class="bg-cover pd-header post-cover" style="background-image: url('/medias/featureimages/18.jpg')">
    <div class="container" style="right: 0px;left: 0px;">
        <div class="row">
            <div class="col s12 m12 l12">
                <div class="brand">
                    <h1 class="description center-align post-title">Android view的绘制流程</h1>
                </div>
            </div>
        </div>
    </div>
</div>




<main class="container content">

    
    <!-- 文章内容详情 -->
<div id="artDetail">
    <div class="card">
        <div class="card-content article-info">
            <div class="row tag-cate">
                <div class="col s7">
                    
                    <div class="article-tag">
                        
                            <a href="/tags/%E9%9D%A2%E8%AF%95/">
                                <span class="chip bg-color">面试</span>
                            </a>
                        
                            <a href="/tags/Java/">
                                <span class="chip bg-color">Java</span>
                            </a>
                        
                            <a href="/tags/Android/">
                                <span class="chip bg-color">Android</span>
                            </a>
                        
                            <a href="/tags/2020/">
                                <span class="chip bg-color">2020</span>
                            </a>
                        
                    </div>
                    
                </div>
                <div class="col s5 right-align">
                    
                    <div class="post-cate">
                        <i class="fas fa-bookmark fa-fw icon-category"></i>
                        
                            <a href="/categories/%E9%9D%A2%E7%BB%8F/" class="post-category">
                                面经
                            </a>
                        
                            <a href="/categories/%E9%9D%A2%E7%BB%8F/Java%E5%9F%BA%E7%A1%80/" class="post-category">
                                Java基础
                            </a>
                        
                            <a href="/categories/%E9%9D%A2%E7%BB%8F/Java%E5%9F%BA%E7%A1%80/Android/" class="post-category">
                                Android
                            </a>
                        
                    </div>
                    
                </div>
            </div>

            <div class="post-info">
                
                <div class="post-date info-break-policy">
                    <i class="far fa-calendar-minus fa-fw"></i>发布日期:&nbsp;&nbsp;
                    2020-08-24
                </div>
                

                

                

                

                
            </div>
        </div>
        <hr class="clearfix">
        <div class="card-content article-card-content">
            <div id="articleContent">
                <h1 id="Android-View的绘制流程"><a href="#Android-View的绘制流程" class="headerlink" title="Android View的绘制流程"></a>Android View的绘制流程</h1><p><em>不要停下脚步，一往无前</em></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>Android View的绘制流程是View相关的核心知识点，也是高阶UI必须要了解的前提。在Android系统中，Window是最基本的窗口单元，每个activity都会创建一个，PhoneWindow是Window的唯一实现类，是View系统和Activity（可以理解为控制器）之前的纽带。Window下有个DecorView,DecorView是一个FrameLayout,是我们自己布局的载体。</p>
<p><img src="" alt="img"></p>
<h2 id="一、window的创建"><a href="#一、window的创建" class="headerlink" title="一、window的创建"></a>一、window的创建</h2><p>startActivity最终会调用到ActivityThread的handleLaunchActivity方法来创建Activity，</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">handleLaunchActivity</span><span class="token punctuation">(</span>ActivityClientRecord r<span class="token punctuation">,</span> Intent customIntent<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token comment" spellcheck="true">// 创建Activity，会调用Activity的onCreate方法</span>
    <span class="token comment" spellcheck="true">// 从而完成window的创建</span>
    Activity a <span class="token operator">=</span> <span class="token function">performLaunchActivity</span><span class="token punctuation">(</span>r<span class="token punctuation">,</span> customIntent<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>a <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        r<span class="token punctuation">.</span>createdConfig <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Configuration</span><span class="token punctuation">(</span>mConfiguration<span class="token punctuation">)</span><span class="token punctuation">;</span>
        Bundle oldState <span class="token operator">=</span> r<span class="token punctuation">.</span>state<span class="token punctuation">;</span>
        <span class="token function">handleResumeActivity</span><span class="token punctuation">(</span>r<span class="token punctuation">.</span>tolen<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">,</span> r<span class="token punctuation">.</span>isForward<span class="token punctuation">,</span> <span class="token operator">!</span>r<span class="token punctuation">.</span>activity<span class="token punctuation">.</span><span class="token punctuation">.</span>mFinished <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>r<span class="token punctuation">.</span>startsNotResumed<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>具体的创建过程是在performLaunchActivity方法中完成的，代码如下：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">private</span> Activity <span class="token function">performLaunchActivity</span><span class="token punctuation">(</span>ActivityClientRecord r<span class="token punctuation">,</span> Intent customIntent<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
                <span class="token comment" spellcheck="true">// 根据反射创建activity</span>
        Activity activity <span class="token operator">=</span> null<span class="token punctuation">;</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>ClassLoader cl <span class="token operator">=</span> r<span class="token punctuation">.</span>packageInfo<span class="token punctuation">.</span><span class="token function">getClassLoader</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            activity <span class="token operator">=</span> mInstrumentation<span class="token punctuation">.</span><span class="token function">newActivity</span><span class="token punctuation">(</span>
                    cl<span class="token punctuation">,</span> component<span class="token punctuation">.</span><span class="token function">getClassName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> r<span class="token punctuation">.</span>intent<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span> 
            <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token keyword">try</span> <span class="token punctuation">{</span>
            Application app <span class="token operator">=</span> r<span class="token punctuation">.</span>packageInfo<span class="token punctuation">.</span><span class="token function">makeApplication</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> mInstrumentation<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>activity <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment" spellcheck="true">// ......           </span>
                Window window <span class="token operator">=</span> null<span class="token punctuation">;</span>
                <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
                <span class="token comment" spellcheck="true">// actitiy和window绑定</span>
                activity<span class="token punctuation">.</span><span class="token function">attach</span><span class="token punctuation">(</span>appContext<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token function">getInstrumentation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> r<span class="token punctuation">.</span>token<span class="token punctuation">,</span>
                        r<span class="token punctuation">.</span>ident<span class="token punctuation">,</span> app<span class="token punctuation">,</span> r<span class="token punctuation">.</span>intent<span class="token punctuation">,</span> r<span class="token punctuation">.</span>activityInfo<span class="token punctuation">,</span> title<span class="token punctuation">,</span> r<span class="token punctuation">.</span>parent<span class="token punctuation">,</span>
                        r<span class="token punctuation">.</span>embeddedID<span class="token punctuation">,</span> r<span class="token punctuation">.</span>lastNonConfigurationInstances<span class="token punctuation">,</span> config<span class="token punctuation">,</span>
                        r<span class="token punctuation">.</span>referrer<span class="token punctuation">,</span> r<span class="token punctuation">.</span>voiceInteractor<span class="token punctuation">,</span> window<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span> 
            <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token keyword">return</span> activity<span class="token punctuation">;</span>
    <span class="token punctuation">}</span></code></pre>
<p>activity的attach方法，将window与activity绑定：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">attach</span><span class="token punctuation">(</span>Context context<span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">,</span>Window window<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">attachBaseContext</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mFragments<span class="token punctuation">.</span><span class="token function">attachHost</span><span class="token punctuation">(</span>null <span class="token comment" spellcheck="true">/*parent*/</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment" spellcheck="true">// 创建PhoneWindow，并赋值给activity的mWindow成员</span>
        mWindow <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">PhoneWindow</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> window<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mWindow<span class="token punctuation">.</span><span class="token function">setWindowControllerCallback</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        mWindow<span class="token punctuation">.</span><span class="token function">setCallback</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        mWindow<span class="token punctuation">.</span><span class="token function">setOnWindowDismissedCallback</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        mWindow<span class="token punctuation">.</span><span class="token function">getLayoutInflater</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setPrivateFactory</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="二、DecorView的创建和加载"><a href="#二、DecorView的创建和加载" class="headerlink" title="二、DecorView的创建和加载"></a>二、DecorView的创建和加载</h2><p>创建好Activity，并且与创建好的Window绑定后，会调用ActivityThread的handleResumeActivity方法</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">handleResumeActivity</span><span class="token punctuation">(</span>IBinder token<span class="token punctuation">,</span><span class="token keyword">boolean</span> clearHide<span class="token punctuation">,</span> <span class="token keyword">boolean</span> isForward<span class="token punctuation">,</span>     <span class="token keyword">boolean</span> reallyResume<span class="token punctuation">,</span> <span class="token keyword">int</span> seq<span class="token punctuation">,</span> String reason<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token function">unscheduleGcIdler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    mSomeActivitiesChanged <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>

    <span class="token comment" spellcheck="true">// 调用activity的onResume方法</span>
    r <span class="token operator">=</span> <span class="token function">performResumeActivity</span><span class="token punctuation">(</span>token<span class="token punctuation">,</span> clearHide<span class="token punctuation">,</span> reason<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span> <span class="token punctuation">(</span>r <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> Activity a <span class="token operator">=</span> r<span class="token punctuation">.</span>activity<span class="token punctuation">;</span>
                <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>r<span class="token punctuation">.</span>window <span class="token operator">==</span> null <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>a<span class="token punctuation">.</span>mFinished <span class="token operator">&amp;&amp;</span> willBeVisible<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            r<span class="token punctuation">.</span>window <span class="token operator">=</span> r<span class="token punctuation">.</span>activity<span class="token punctuation">.</span><span class="token function">getWindow</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment" spellcheck="true">// 获取到window中的decorView</span>
            View decor <span class="token operator">=</span> r<span class="token punctuation">.</span>window<span class="token punctuation">.</span><span class="token function">getDecorView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            decor<span class="token punctuation">.</span><span class="token function">setVisibility</span><span class="token punctuation">(</span>View<span class="token punctuation">.</span>INVISIBLE<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token comment" spellcheck="true">// 得到了WindowManager，WindowManager是一个接口</span>
            <span class="token comment" spellcheck="true">// 并且继承了接口ViewManager</span>
            ViewManager wm <span class="token operator">=</span> a<span class="token punctuation">.</span><span class="token function">getWindowManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            WindowManager<span class="token punctuation">.</span>LayoutParams l <span class="token operator">=</span> r<span class="token punctuation">.</span>window<span class="token punctuation">.</span><span class="token function">getAttributes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            a<span class="token punctuation">.</span>mDecor <span class="token operator">=</span> decor<span class="token punctuation">;</span>
            l<span class="token punctuation">.</span>type <span class="token operator">=</span> WindowManager<span class="token punctuation">.</span>LayoutParams<span class="token punctuation">.</span>TYPE_BASE_APPLICATION<span class="token punctuation">;</span>
            l<span class="token punctuation">.</span>softInputMode <span class="token operator">|=</span> forwardBit<span class="token punctuation">;</span>
            <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
            <span class="token comment" spellcheck="true">// 实际调用的是WindowManagerImpl(WindowManager接口实现类)的addView方法</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>a<span class="token punctuation">.</span>mVisibleFromClient <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>a<span class="token punctuation">.</span>mWindowAdded<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                a<span class="token punctuation">.</span>mWindowAdded <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
                wm<span class="token punctuation">.</span><span class="token function">addView</span><span class="token punctuation">(</span>decor<span class="token punctuation">,</span> l<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token punctuation">}</span> 
       <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>除了Window和DecorView这两个主力之外，还有一个很重要的角色是ViewRoot,ViewRoot是连接WindowManager和DecorView之间的纽带，View的三大流程均由其来完成。在ActivityThread中，当Activity对象被创建完毕后，会将DecorView添加到Window中，同时会创建ViewRootImpl对象，并将ViewRootImpl对象和DecorView建立关联，相关源码如下所示：</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">// WindowManagerGlobal的addView方法中</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addView</span><span class="token punctuation">(</span>View view<span class="token punctuation">,</span> ViewGroup<span class="token punctuation">.</span>LayoutParams params<span class="token punctuation">,</span>
        Display display<span class="token punctuation">,</span> Window parentWindow<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    ViewRootImpl root<span class="token punctuation">;</span>
    View panelParentView <span class="token operator">=</span> null<span class="token punctuation">;</span>

    <span class="token keyword">synchronized</span> <span class="token punctuation">(</span>mLock<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
        <span class="token comment" spellcheck="true">// 创建ViewRootImpl实例</span>
        root <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ViewRootImpl</span><span class="token punctuation">(</span>view<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> display<span class="token punctuation">)</span><span class="token punctuation">;</span>
        view<span class="token punctuation">.</span><span class="token function">setLayoutParams</span><span class="token punctuation">(</span>wparams<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mViews<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>view<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mRoots<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>root<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mParams<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>wparams<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// 把DecorView加载到Window中</span>
        root<span class="token punctuation">.</span><span class="token function">setView</span><span class="token punctuation">(</span>view<span class="token punctuation">,</span> wparams<span class="token punctuation">,</span> panelParentView<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">RuntimeException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// BadTokenException or InvalidDisplayException, clean up.</span>
        <span class="token keyword">synchronized</span> <span class="token punctuation">(</span>mLock<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">final</span> <span class="token keyword">int</span> index <span class="token operator">=</span> <span class="token function">findViewLocked</span><span class="token punctuation">(</span>view<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token function">removeViewLocked</span><span class="token punctuation">(</span>index<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">throw</span> e<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h2 id="三、绘制的整体流程"><a href="#三、绘制的整体流程" class="headerlink" title="三、绘制的整体流程"></a>三、绘制的整体流程</h2><p>整个绘图流程在<code>ViewRoot</code>类的<code>performTraversals()</code>函数展开，该函数所做 的工作可简单概况为是否需要重新计算视图大小(<code>measure</code>)、是否需要重新安置视图的位置(<code>layout</code>)、以及是否需要重绘(<code>draw</code>)</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">performTraversals</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token comment" spellcheck="true">//最外层ViewGroup是MATCH_PARENT,在实例被创建时确定</span>
    <span class="token keyword">int</span> childWidthMeasureSpec <span class="token operator">=</span> <span class="token function">getRootMeasureSpec</span><span class="token punctuation">(</span>mWidth<span class="token punctuation">,</span> lp<span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> childHeightMeasureSpec <span class="token operator">=</span> <span class="token function">getRootMeasureSpec</span><span class="token punctuation">(</span>mHeight<span class="token punctuation">,</span> lp<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token comment" spellcheck="true">//测量流程</span>
    <span class="token function">performMeasure</span><span class="token punctuation">(</span>childWidthMeasureSpec<span class="token punctuation">,</span> childHeightMeasureSpec<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token comment" spellcheck="true">//布局流程</span>
    <span class="token function">performLayout</span><span class="token punctuation">(</span>lp<span class="token punctuation">,</span> mWidth<span class="token punctuation">,</span> mHeight<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token comment" spellcheck="true">//绘制流程</span>
    <span class="token function">performDraw</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span></code></pre>
<p>大概的流程图如下：</p>
<p><img src="" alt="img"></p>
<h3 id="0-MeasureSpec"><a href="#0-MeasureSpec" class="headerlink" title="0.MeasureSpec"></a>0.MeasureSpec</h3><p>需要先了解MeasureSpec，它是一个32位的整形值，其高2位表示测量模式SpecMode,低30位表示某个测试模式下的规格大小SpecSize。</p>
<p>测量模式有三种：</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">// 不指定模式, 父视图没有限制子视图的大小，子视图可以是想要</span>
<span class="token comment" spellcheck="true">// 的任何尺寸，通常用于系统内部，应用开发中很少用到。</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> UNSPECIFIED <span class="token operator">=</span> <span class="token number">0</span> <span class="token operator">&lt;&lt;</span> MODE_SHIFT<span class="token punctuation">;</span>

<span class="token comment" spellcheck="true">// 精确模式，视图宽高指定为match_parent或具体数值时生效，</span>
<span class="token comment" spellcheck="true">// 表示父视图已经决定了子视图的精确大小，这种模式下View的测量</span>
<span class="token comment" spellcheck="true">// 值就是SpecSize的值。</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> EXACTLY     <span class="token operator">=</span> <span class="token number">1</span> <span class="token operator">&lt;&lt;</span> MODE_SHIFT<span class="token punctuation">;</span>

<span class="token comment" spellcheck="true">// 最大值测量模式，当视图的宽高指定为wrap_content时生效，此时</span>
<span class="token comment" spellcheck="true">// 子视图的尺寸可以是不超过父视图允许的最大尺寸的任何尺寸。</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span> AT_MOST     <span class="token operator">=</span> <span class="token number">2</span> <span class="token operator">&lt;&lt;</span> MODE_SHIFT<span class="token punctuation">;</span></code></pre>
<h4 id="1-DocerView的MeasureSpec创建"><a href="#1-DocerView的MeasureSpec创建" class="headerlink" title="1) DocerView的MeasureSpec创建"></a>1) DocerView的MeasureSpec创建</h4><pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//desiredWindowWidth和desiredWindowHeight是屏幕的尺寸</span>
childWidthMeasureSpec <span class="token operator">=</span> <span class="token function">getRootMeasureSpec</span><span class="token punctuation">(</span>desiredWindowWidth<span class="token punctuation">,</span> lp<span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">;</span>
childHeightMeasureSpec <span class="token operator">=</span> <span class="token function">getRootMeasureSpec</span><span class="token punctuation">(</span>desiredWindowHeight<span class="token punctuation">,</span> lp<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">performMeasure</span><span class="token punctuation">(</span>childWidthMeasureSpec<span class="token punctuation">,</span> childHeightMeasureSpec<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">getRootMeaureSpec</span><span class="token punctuation">(</span><span class="token keyword">int</span> windowSize<span class="token punctuation">,</span> <span class="token keyword">int</span> rootDimension<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> measureSpec<span class="token punctuation">;</span>
    <span class="token keyword">switch</span> <span class="token punctuation">(</span>rootDimension<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">case</span> ViewGroup<span class="token punctuation">.</span>LayoutParams<span class="token punctuation">.</span>MATRCH_PARENT<span class="token operator">:</span>
            <span class="token comment" spellcheck="true">// Window can't resize. Force root view to be windowSize.</span>
            measureSpec <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span><span class="token function">makeMeasureSpec</span><span class="token punctuation">(</span>windowSize<span class="token punctuation">,</span> MeasureSpec<span class="token punctuation">.</span>EXACTLY<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token keyword">case</span> ViewGroup<span class="token punctuation">.</span>LayoutParams<span class="token punctuation">.</span>WRAP_CONTENT：
            <span class="token comment" spellcheck="true">// Window can resize. Set max size for root view.</span>
            measureSpec <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span><span class="token function">makeMeasureSpec</span><span class="token punctuation">(</span>windowSize<span class="token punctuation">,</span> MeasureSpec<span class="token punctuation">.</span>AT_MOST<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">break</span>
        <span class="token keyword">default</span><span class="token operator">:</span>
            <span class="token comment" spellcheck="true">// Window wants to be an exact size. Force root view to be that size.</span>
            measureSpec <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span><span class="token function">makeMeasureSpec</span><span class="token punctuation">(</span>rootDimension<span class="token punctuation">,</span> MeasureSpec<span class="token punctuation">.</span>EXACTLY<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> measureSpec<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h4 id="2）子View的MeasureSpec创建"><a href="#2）子View的MeasureSpec创建" class="headerlink" title="2）子View的MeasureSpec创建"></a>2）子View的MeasureSpec创建</h4><p>子View的MeasureSpec值是根据子View的布局参数（LayoutParams）和父容器的MeasureSpec值计算得来的，具 体计算逻辑封装在getChildMeasureSpec()里。</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">/**
*
* 目标是将父控件的测量规格和child view的布局参数LayoutParams相结合，得到一个 * 最可能符合条件的child *    view的测量规格。
* @param spec 父控件的测量规格
* @param padding 父控件里已经占用的大小
* @param childDimension child view布局LayoutParams里的尺寸
* @return child view 的测量规格
*/</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">getChildMeasureSpec</span><span class="token punctuation">(</span><span class="token keyword">int</span> spec<span class="token punctuation">,</span> <span class="token keyword">int</span> padding<span class="token punctuation">,</span> <span class="token keyword">int</span> childDimesion<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> specMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span><span class="token function">getMode</span><span class="token punctuation">(</span>spec<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//父控件的测量模式</span>
    <span class="token keyword">int</span> specSize <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span><span class="token function">getSize</span><span class="token punctuation">(</span>spec<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment" spellcheck="true">//父控件的测量大小</span>

    <span class="token comment" spellcheck="true">// padding是指父容器中已占用的空间大小，因此子元素可用的</span>
    <span class="token comment" spellcheck="true">// 大小为父容器的尺寸减去padding</span>
    <span class="token keyword">int</span> size <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> specSize <span class="token operator">-</span> padding<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">int</span> resultSize <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> resultMode <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token keyword">switch</span> <span class="token punctuation">(</span>sepcMode<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// 当父控件的测量模式 是 精确模式，也就是有精确的尺寸了 </span>
        <span class="token keyword">case</span> MeasureSpec<span class="token punctuation">.</span>EXACTLY<span class="token operator">:</span>
                <span class="token comment" spellcheck="true">//如果child的布局参数有固定值，比如"layout_width" = "100dp"</span>
                        <span class="token comment" spellcheck="true">//那么显然child的测量规格也可以确定下来了，测量大小就是100dp，测量模式也是EXACTLY</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimension <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                resultSize <span class="token operator">=</span> childDimension<span class="token punctuation">;</span>
                resultMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span>EXACTLY<span class="token punctuation">;</span>
            <span class="token punctuation">}</span> 
                <span class="token comment" spellcheck="true">//如果child的布局参数是"match_parent"，也就是想要占满父控件</span>
                <span class="token comment" spellcheck="true">//而此时父控件是精确模式，也就是能确定自己的尺寸了，那child也能确定自己大小了</span>
                <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimension <span class="token operator">==</span> LayoutParams<span class="token punctuation">.</span>MATCH_PARENT<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment" spellcheck="true">// Child wants to be our size. So be it.</span>
                resultSize <span class="token operator">=</span> size<span class="token punctuation">;</span>
                resultMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span>EXACTLY<span class="token punctuation">;</span>
            <span class="token punctuation">}</span> 
                <span class="token comment" spellcheck="true">//如果child的布局参数是"wrap_content"，也就是想要根据自己的逻辑决定自己大小， </span>
                <span class="token comment" spellcheck="true">//比如TextView根据设置的字符串大小来决定自己的大小</span>
                        <span class="token comment" spellcheck="true">//那就自己决定自己的大小，不过你的大小肯定不能大于父控件的大小</span>
                        <span class="token comment" spellcheck="true">//所以测量模式就是AT_MOST，测量大小就是父控件的size</span>
                <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimesion <span class="token operator">==</span> LayoutParams<span class="token punctuation">.</span>WRAP_CONTENT<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                resultSize <span class="token operator">=</span> size<span class="token punctuation">;</span>
                resultMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span>AT_MOST<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>

        <span class="token comment" spellcheck="true">// 当父控件的测量模式 是 最大模式，也就是说父控件自己还不知道自己的尺寸，但是大小不能超过size </span>
        <span class="token keyword">case</span> MeasureSpec<span class="token punctuation">.</span>AT_MOST<span class="token operator">:</span>
                <span class="token comment" spellcheck="true">//同样的，既然child能确定自己大小，尽管父控件自己还不知道自己大小，也优先满足孩子的需求</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimension <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                resultSize <span class="token operator">=</span> childDimension<span class="token punctuation">;</span>
                resultMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span>EXACTLY<span class="token punctuation">;</span>
            <span class="token punctuation">}</span> 
                <span class="token comment" spellcheck="true">//child想要和父控件一样大，但父控件自己也不确定自己大小，所以child也无法确定自己大小 </span>
                <span class="token comment" spellcheck="true">//但同样的，child的尺寸上限也是父控件的尺寸上限size</span>
                <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimension <span class="token operator">==</span> LayoutParams<span class="token punctuation">.</span>MATCH_PARENT<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                resultSize <span class="token operator">=</span> size<span class="token punctuation">;</span>
                resultMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span>AT_MOST<span class="token punctuation">;</span>
            <span class="token punctuation">}</span> 
                <span class="token comment" spellcheck="true">//child想要根据自己逻辑决定大小，那就自己决定自己的尺寸，但不能超过父控件</span>
                <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimension <span class="token operator">==</span> LayoutParams<span class="token punctuation">.</span>WRAP_CONTENT<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                resultSize <span class="token operator">=</span> size<span class="token punctuation">;</span>
                resultMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span>AT_MOST<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>

        <span class="token comment" spellcheck="true">// Parent asked to see how big we want to be</span>
        <span class="token keyword">case</span> MeasureSpec<span class="token punctuation">.</span>UNSPECIFIED<span class="token operator">:</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimension <span class="token operator">>=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment" spellcheck="true">// Child wants a specific size... let him have it</span>
                resultSize <span class="token operator">=</span> childDimension<span class="token punctuation">;</span>
                resultMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span>EXACTLY<span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimension <span class="token operator">==</span> LayoutParams<span class="token punctuation">.</span>MATCH_PARENT<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment" spellcheck="true">// Child wants to be our size... find out how big it should be</span>
                resultSize <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
                resultMode <span class="token operator">=</span> MeasureSpec<span class="token punctuation">.</span>UNSPECIFIED<span class="token punctuation">;</span>
            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>childDimension <span class="token operator">==</span> LayoutParams<span class="token punctuation">.</span>WRAP_CONTENT<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token comment" spellcheck="true">// Child wants to determine its own size....</span>
                <span class="token comment" spellcheck="true">// find out how big it should be</span>
                resultSize <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
                resultMode <span class="token operator">==</span> MeasureSpec<span class="token punctuation">.</span>UNSPECIFIED<span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token keyword">return</span> MeasureSpec<span class="token punctuation">.</span><span class="token function">makeMeasureSpec</span><span class="token punctuation">(</span>resultSize<span class="token punctuation">,</span> resultMode<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到，对于应用层 View ，其 MeasureSpec 由父容器的 MeasureSpec 和自身的 LayoutParams 来共同决定对于不同的父容器和view本身不同的LayoutParams，view就可以有多种MeasureSpec。</p>
<ol>
<li>当view采用固定宽 高的时候，不管父容器的MeasureSpec是什么，view的MeasureSpec都是精确模式并且其大小遵循Layoutparams中的大小；</li>
<li>当view的宽高是match_parent时，这个时候如果父容器的模式是精准模式，那么 view也是精准模式并且其大小是父容器的剩余空间，如果父容器是最大模式，那么view也是最大模式并且其大小不会超过父容器的剩余空间；</li>
<li>当view的宽高是wrap_content时，不管父容器的模式是精准还是最大化，view的模式总是最大化并且大小不能超过父容器的剩余空间。</li>
<li>Unspeciﬁed模式，这个模式主要用于系统内 部多次measure的情况下，一般来说，我们不需要关注此模式。</li>
</ol>
<h3 id="1-measure流程"><a href="#1-measure流程" class="headerlink" title="1. measure流程"></a>1. measure流程</h3><p>测试流程从ViewRootImpl.performMeasure()开始：</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//=============ViewRootImpl.java==============</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">performMeasure</span><span class="token punctuation">(</span><span class="token keyword">int</span> childWidthMeasureSpec<span class="token punctuation">,</span> <span class="token keyword">int</span> childHeightMeasureSpec<span class="token punctuation">)</span> <span class="token punctuation">{</span>
       <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
       mView<span class="token punctuation">.</span><span class="token function">measure</span><span class="token punctuation">(</span>childWidthMeasureSpec<span class="token punctuation">,</span> childHeightMeasureSpec<span class="token punctuation">)</span><span class="token punctuation">;</span>
       <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span></code></pre>
<p>此处的mView在<code>ViewRootImpl</code>的<code>setView</code>方法中赋值</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//=============ViewRootImpl.java==============</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setView</span><span class="token punctuation">(</span>View view<span class="token punctuation">,</span> WindowManager<span class="token punctuation">.</span>LayoutParams attrs<span class="token punctuation">,</span> View panelParentView<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
      <span class="token comment" spellcheck="true">// 此处的view，就是在ActivityThread的addView方法中传过来的，也就是DecorView</span>
      mView <span class="token operator">=</span> view<span class="token punctuation">;</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
      <span class="token comment" spellcheck="true">// 此处attrs，就是在ActivityThread的addView方法中传过来的</span>
      mWindowAttributes<span class="token punctuation">.</span><span class="token function">copyFrom</span><span class="token punctuation">(</span>attrs<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到，从ViewRootImpl的performMeasure方法开始，一开始进行测试流程的就是从<code>DecorView</code>的<code>measure()</code>操作开始的，追踪代码进入到View的<code>measure()</code>方法：</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//=============View.java==============</span>
<span class="token comment" spellcheck="true">/**
 * &lt;p>
 * This is called to find out how big a view should be. The parent
 * supplies constraint information in the width and height parameters.
 * &lt;/p>
 *
 * &lt;p>
 * The actual measurement work of a view is performed in
 * {@link #onMeasure(int, int)}, called by this method. Therefore, only
 * {@link #onMeasure(int, int)} can and must be overridden by subclasses.
    view的实际测量工作是在onMeasure()方法中完成的，其子类可以并且必须实现该方法。
 * &lt;/p>
 *
 *
 * @param widthMeasureSpec Horizontal space requirements as imposed by the
 *        parent
 * @param heightMeasureSpec Vertical space requirements as imposed by the
 *        parent
 *
 * @see #onMeasure(int, int)
 */</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">measure</span><span class="token punctuation">(</span><span class="token keyword">int</span> widthMeasureSpec<span class="token punctuation">,</span> <span class="token keyword">int</span> heightMeasureSpec<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token comment" spellcheck="true">// measure ourselves, this should set the measured dimension flag back</span>
    <span class="token function">onMeasure</span><span class="token punctuation">(</span>widthMeasureSpec<span class="token punctuation">,</span> heightMeasureSpec<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>       
<span class="token punctuation">}</span></code></pre>
<p>再看我们熟悉的这个<code>onMeasure(int,int)</code>方法：</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">//=============View.java==============</span>
<span class="token operator">*</span><span class="token operator">*</span>
<span class="token operator">*</span> <span class="token operator">&lt;</span>p<span class="token operator">></span>
<span class="token operator">*</span> Measure the view and its content to determine the measured width and the
<span class="token operator">*</span> measured height<span class="token punctuation">.</span> This method is invoked by <span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> #<span class="token function">measure</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">}</span> and
<span class="token operator">*</span> should be overridden by subclasses to provide accurate and efficient
<span class="token operator">*</span> measurement of their contents<span class="token punctuation">.</span>
<span class="token operator">*</span> <span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span>
<span class="token operator">*</span>
<span class="token operator">*</span> <span class="token operator">&lt;</span>p<span class="token operator">></span>
<span class="token operator">*</span> <span class="token operator">&lt;</span>strong<span class="token operator">></span>CONTRACT<span class="token operator">:</span><span class="token operator">&lt;</span><span class="token operator">/</span>strong<span class="token operator">></span> When overriding <span class="token keyword">this</span> method<span class="token punctuation">,</span> you
<span class="token operator">*</span> <span class="token operator">&lt;</span>em<span class="token operator">></span>must<span class="token operator">&lt;</span><span class="token operator">/</span>em<span class="token operator">></span> call <span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> #<span class="token function">setMeasuredDimension</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">}</span> to store the
<span class="token operator">*</span> measured width and height of <span class="token keyword">this</span> view<span class="token punctuation">.</span> Failure to <span class="token keyword">do</span> so will trigger an
<span class="token operator">*</span> <span class="token operator">&lt;</span>code<span class="token operator">></span>IllegalStateException<span class="token operator">&lt;</span><span class="token operator">/</span>code<span class="token operator">></span><span class="token punctuation">,</span> thrown by
<span class="token operator">*</span> <span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> #<span class="token function">measure</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">.</span> Calling the superclass'
<span class="token operator">*</span> <span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> #<span class="token function">onMeasure</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">}</span> is a valid use<span class="token punctuation">.</span>
<span class="token operator">*</span> <span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span>
<span class="token operator">*</span>
<span class="token operator">*</span> <span class="token operator">&lt;</span>p<span class="token operator">></span>
<span class="token operator">*</span> The base <span class="token keyword">class</span> <span class="token class-name">implementation</span> of measure defaults to the background size<span class="token punctuation">,</span>
<span class="token operator">*</span> unless a larger size is allowed by the MeasureSpec<span class="token punctuation">.</span> Subclasses should
<span class="token operator">*</span> override <span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> #<span class="token function">onMeasure</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">)</span><span class="token punctuation">}</span> to provide better measurements of
<span class="token operator">*</span> their content<span class="token punctuation">.</span>
<span class="token operator">*</span> <span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span>
<span class="token operator">*</span>
<span class="token operator">*</span> <span class="token operator">&lt;</span>p<span class="token operator">></span>
<span class="token operator">*</span> If <span class="token keyword">this</span> method is overridden<span class="token punctuation">,</span> it is the subclass's responsibility to make
<span class="token operator">*</span> sure the measured height and width are at least the view's minimum height
<span class="token operator">*</span> and <span class="token function">width</span> <span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> #<span class="token function">getSuggestedMinimumHeight</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span> and
<span class="token operator">*</span> <span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> #<span class="token function">getSuggestedMinimumWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span>
<span class="token operator">*</span> <span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span>
<span class="token operator">*</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@param</span> widthMeasureSpec horizontal space requirements as imposed by the parent<span class="token punctuation">.</span>
<span class="token operator">*</span>                         The requirements are encoded with
<span class="token operator">*</span>                         <span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> android<span class="token punctuation">.</span>view<span class="token punctuation">.</span>View<span class="token punctuation">.</span>MeasureSpec<span class="token punctuation">}</span><span class="token punctuation">.</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@param</span> heightMeasureSpec vertical space requirements as imposed by the parent<span class="token punctuation">.</span>
<span class="token operator">*</span>                         The requirements are encoded with
<span class="token operator">*</span>                         <span class="token punctuation">{</span><span class="token annotation punctuation">@link</span> android<span class="token punctuation">.</span>view<span class="token punctuation">.</span>View<span class="token punctuation">.</span>MeasureSpec<span class="token punctuation">}</span><span class="token punctuation">.</span>
<span class="token operator">*</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@see</span> #<span class="token function">getMeasuredWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@see</span> #<span class="token function">getMeasuredHeight</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@see</span> #<span class="token function">setMeasuredDimension</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">,</span> <span class="token keyword">int</span><span class="token punctuation">)</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@see</span> #<span class="token function">getSuggestedMinimumHeight</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@see</span> #<span class="token function">getSuggestedMinimumWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@see</span> android<span class="token punctuation">.</span>view<span class="token punctuation">.</span>View<span class="token punctuation">.</span>MeasureSpec#<span class="token function">getMode</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>
<span class="token operator">*</span> <span class="token annotation punctuation">@see</span> android<span class="token punctuation">.</span>view<span class="token punctuation">.</span>View<span class="token punctuation">.</span>MeasureSpec#<span class="token function">getSize</span><span class="token punctuation">(</span><span class="token keyword">int</span><span class="token punctuation">)</span>
<span class="token operator">*</span><span class="token operator">/</span>
<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">onMeasure</span><span class="token punctuation">(</span><span class="token keyword">int</span> widthMeasureSpec<span class="token punctuation">,</span> <span class="token keyword">int</span> heightMeasureSpec<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">setMeasuredDimension</span><span class="token punctuation">(</span><span class="token function">getDefaultSize</span><span class="token punctuation">(</span><span class="token function">getSuggestedMinimumWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> widthMeasureSpec<span class="token punctuation">)</span><span class="token punctuation">,</span>
            <span class="token function">getDefaultSize</span><span class="token punctuation">(</span><span class="token function">getSuggestedMinimumHeight</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> heightMeasureSpec<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>方法很短，注释却很长，注意注释的第二段：当重写这个方法时，你必须调用<code>setMeasuredDimension(int, int)</code>方法来保存View的宽高尺寸，不然的话，会抛出IllegalStateException异常。此方法的调用，也代表着测量阶段的结束。</p>
<p>对于ViewGroup的测量，主要是通过measureChild方法：</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">/**
 * 请求所有的子View去测量自己, 要考虑到子View的测量要求MeasureSpec及其padding.
 * 会跳过所有状态为GONE的子View, 最主要的工作是在getChildMeasureSpec方法中处理的

 * @param widthMeasureSpec The width requirements for this view
 * @param heightMeasureSpec The height requirements for this view
 */</span>
<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">measureChildren</span><span class="token punctuation">(</span><span class="token keyword">int</span> widthMeasureSpec<span class="token punctuation">,</span> <span class="token keyword">int</span> heightMeasureSpec<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> <span class="token keyword">int</span> size <span class="token operator">=</span> mChildrenCount<span class="token punctuation">;</span>
    <span class="token keyword">final</span> View<span class="token punctuation">[</span><span class="token punctuation">]</span> children <span class="token operator">=</span> mChildren<span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> size<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> View child <span class="token operator">=</span> children<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>child<span class="token punctuation">.</span>mViewFlags <span class="token operator">&amp;</span> VISIBILITY_MASK<span class="token punctuation">)</span> <span class="token operator">!=</span> GONE<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token function">measureChild</span><span class="token punctuation">(</span>child<span class="token punctuation">,</span> widthMeasureSpec<span class="token punctuation">,</span> heightMeasureSpec<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">measureChild</span><span class="token punctuation">(</span>View child<span class="token punctuation">,</span> <span class="token keyword">int</span> parentWidthMeasureSpec<span class="token punctuation">,</span>
        <span class="token keyword">int</span> parentHeightMeasureSpec<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">final</span> LayoutParams lp <span class="token operator">=</span> child<span class="token punctuation">.</span><span class="token function">getLayoutParams</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token keyword">int</span> childWidthMeasureSpec <span class="token operator">=</span> <span class="token function">getChildMeasureSpec</span><span class="token punctuation">(</span>parentWidthMeasureSpec<span class="token punctuation">,</span>
            mPaddingLeft <span class="token operator">+</span> mPaddingRight<span class="token punctuation">,</span> lp<span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">final</span> <span class="token keyword">int</span> childHeightMeasureSpec <span class="token operator">=</span> <span class="token function">getChildMeasureSpec</span><span class="token punctuation">(</span>parentHeightMeasureSpec<span class="token punctuation">,</span>
            mPaddingTop <span class="token operator">+</span> mPaddingBottom<span class="token punctuation">,</span> lp<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">;</span>
    child<span class="token punctuation">.</span><span class="token function">measure</span><span class="token punctuation">(</span>childWidthMeasureSpec<span class="token punctuation">,</span> childHeightMeasureSpec<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment" spellcheck="true">/** 
  * 最繁重的工作都在此方法中，也就是为每个子View计算出它的测量规则MeasureSpec
  * 此方法在对上一小节"子View的MeasureSpec创建"的介绍中已经分析过。
  * 目标是将 ChildView 的 MeasureSpec 和 LayoutParams 结合起来去得到一个最合适的结果。
  *
  * @param spec 对该 View 的测绘要求
  * @param padding 当前 View 在当前唯独上的 paddingand，也有可能含有 margins
  *
  * @param childDimension 在当前维度上（height 或 width）的具体指
  * @return 子视图的 MeasureSpec 
  */</span>
 <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">getChildMeasureSpec</span><span class="token punctuation">(</span><span class="token keyword">int</span> spec<span class="token punctuation">,</span> <span class="token keyword">int</span> padding<span class="token punctuation">,</span> <span class="token keyword">int</span> childDimension<span class="token punctuation">)</span> <span class="token punctuation">{</span>
     <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
     <span class="token comment" spellcheck="true">// 根据获取到的子视图的测量要求和大小创建子视图的 MeasureSpec</span>
     <span class="token keyword">return</span> MeasureSpec<span class="token punctuation">.</span><span class="token function">makeMeasureSpec</span><span class="token punctuation">(</span>resultSize<span class="token punctuation">,</span> resultMode<span class="token punctuation">)</span><span class="token punctuation">;</span>  
 <span class="token punctuation">}</span></code></pre>
<p>然后回到了开始所提及的View的measure()-&gt;onMeasure()-&gt;setDimention()方法。</p>
<h3 id="2-layout流程"><a href="#2-layout流程" class="headerlink" title="2.layout流程"></a>2.layout流程</h3><p>首先子View的具体位置是相对于父View而言的，View类的onLayout()方法不需要重写,ViewGroup的onLayout是一个抽象方法，必须要实现这一方法。</p>
<p>layout过程，就是通过测量后的尺寸，获取到view的mMeasuredWidth和mMeasuredHeight,然后通过子View的<code>layout(l,t,r,b)</code>方法来确定子View在父布局中的相对位置。</p>
<p>从ViewRootImpl的performLayout方法开始：</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">performLayout</span><span class="token punctuation">(</span>WindowManager<span class="token punctuation">.</span>LayoutParams lp<span class="token punctuation">,</span> <span class="token keyword">int</span> desiredWindowWidth<span class="token punctuation">,</span>
                           <span class="token keyword">int</span> desiredWindowHeight<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  ···
    <span class="token comment" spellcheck="true">//host，也就是setView方法传进来的DecorView</span>
    <span class="token keyword">final</span> View host <span class="token operator">=</span> mView<span class="token punctuation">;</span>
  ···
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
      <span class="token comment" spellcheck="true">// 调用了DecorView的layout(r,l,t,b)方法，也就是ViewGroup的layout方法</span>
      host<span class="token punctuation">.</span><span class="token function">layout</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> host<span class="token punctuation">.</span><span class="token function">getMeasuredWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> host<span class="token punctuation">.</span><span class="token function">getMeasuredHeight</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      ···
        <span class="token keyword">if</span> <span class="token punctuation">(</span>numViewsRequestingLayout <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
          ···
            <span class="token keyword">if</span> <span class="token punctuation">(</span>validLayoutRequesters <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
              ···
                host<span class="token punctuation">.</span><span class="token function">layout</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> host<span class="token punctuation">.</span><span class="token function">getMeasuredWidth</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> host<span class="token punctuation">.</span><span class="token function">getMeasuredHeight</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
              ···
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
      ···
    <span class="token punctuation">}</span>
  ···
<span class="token punctuation">}</span></code></pre>
<p>然后看ViewGroup的layout：</p>
<pre class=" language-java"><code class="language-java"><span class="token annotation punctuation">@Override</span>
<span class="token comment" spellcheck="true">// 方法被final修饰，和measure一样，不能被修改或重写</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">layout</span><span class="token punctuation">(</span><span class="token keyword">int</span> l<span class="token punctuation">,</span> <span class="token keyword">int</span> t<span class="token punctuation">,</span> <span class="token keyword">int</span> r<span class="token punctuation">,</span> <span class="token keyword">int</span> b<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mSuppressLayout <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>mTransition <span class="token operator">==</span> null <span class="token operator">||</span> <span class="token operator">!</span>mTransition<span class="token punctuation">.</span><span class="token function">isChangingLayout</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>mTransition <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            mTransition<span class="token punctuation">.</span><span class="token function">layoutChange</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment" spellcheck="true">//直接调用了View的layout方法</span>
        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">layout</span><span class="token punctuation">(</span>l<span class="token punctuation">,</span> t<span class="token punctuation">,</span> r<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// record the fact that we noop'd it; request layout when transition finishes</span>
        mLayoutCalledWhileSuppressed <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>再看View的layout方法</p>
<pre class=" language-java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">layout</span><span class="token punctuation">(</span><span class="token keyword">int</span> l<span class="token punctuation">,</span> <span class="token keyword">int</span> t<span class="token punctuation">,</span> <span class="token keyword">int</span> r<span class="token punctuation">,</span> <span class="token keyword">int</span> b<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  ···
    <span class="token keyword">boolean</span> changed <span class="token operator">=</span> <span class="token function">isLayoutModeOptical</span><span class="token punctuation">(</span>mParent<span class="token punctuation">)</span> <span class="token operator">?</span>
    <span class="token function">setOpticalFrame</span><span class="token punctuation">(</span>l<span class="token punctuation">,</span> t<span class="token punctuation">,</span> r<span class="token punctuation">,</span> b<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token function">setFrame</span><span class="token punctuation">(</span>l<span class="token punctuation">,</span> t<span class="token punctuation">,</span> r<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">if</span> <span class="token punctuation">(</span>changed <span class="token operator">||</span> <span class="token punctuation">(</span>mPrivateFlags <span class="token operator">&amp;</span> PFLAG_LAYOUT_REQUIRED<span class="token punctuation">)</span> <span class="token operator">==</span> PFLAG_LAYOUT_REQUIRED<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">onLayout</span><span class="token punctuation">(</span>changed<span class="token punctuation">,</span> l<span class="token punctuation">,</span> t<span class="token punctuation">,</span> r<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">;</span>
    ···
  <span class="token punctuation">}</span>
  ···
<span class="token punctuation">}</span></code></pre>
<p>可以看到，真正进行布局的方法是<code>setOpticalFrame(l,t,r,b)</code>和<code>setFrame(l,t,r,b)</code>方法，而setOpticalFrame里面也是调用了<code>setFrame(l,t,r,b)</code>方法。此方法的四个参数确定了其在父View当中的位置。</p>
<p><code>setFrame(l,t,r,b)</code>方法中会有一个布尔值来判断是否需要对视图进行重绘。</p>
<p>对子View的布局都是通过onLayout()方法中进行的。</p>
<p>布局过程也是通过递归的方式进行的，如果子View仍然是父视图，则会继续layout下去，直到遇到子View的onlayout空方法，则该子View布局流程结束。</p>
<h3 id="3-draw流程"><a href="#3-draw流程" class="headerlink" title="3. draw流程"></a>3. draw流程</h3><p>依然先从ViewRootImpl中的performDraw()方法开始：</p>
<pre class=" language-JAVA"><code class="language-JAVA">// ----------------ViewRootImpl---------------
private void performDraw() {
    ...
    try {
        draw(fullRedrawNeeded);
    } finally {
        ...
    }
    ...
}

private void draw(boolean fullRedrawNeeded) {
    Surface surface = mSurface;
    if (!surface.isValid()) {
        return;
    }
        .......
    if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
            ......
        } else {
            ......
            if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
                return;
            }
        }
    }
    ......
}

    private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,boolean scalingRequired, Rect dirty) {
                                ......
                // 此mView也就是DecorView
                mView.draw(canvas);
                        ......
    }</code></pre>
<p>也就是最终会调用到DecorView的draw(canvas)方法，</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">// ----------------DecorView---------------</span>
<span class="token annotation punctuation">@Override</span>
 <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">draw</span><span class="token punctuation">(</span>Canvas canvas<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// 调用父类的draw方法</span>
     <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">draw</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>

     <span class="token keyword">if</span> <span class="token punctuation">(</span>mMenuBackground <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
         mMenuBackground<span class="token punctuation">.</span><span class="token function">draw</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>跟踪super.draw(canvas)方法，最终会跳到View的draw方法。</p>
<pre class=" language-java"><code class="language-java">   <span class="token comment" spellcheck="true">/**
     * Manually render this view (and all of its children) to the given Canvas.
     * The view must have already done a full layout before this function is
     * called.  When implementing a view, implement
     * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method.
     * If you do need to override this method, call the superclass version.
     *
     * @param canvas The Canvas to which the View is rendered.
     */</span>
    <span class="token annotation punctuation">@CallSuper</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">draw</span><span class="token punctuation">(</span>Canvas canvas<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">final</span> <span class="token keyword">int</span> privateFlags <span class="token operator">=</span> mPrivateFlags<span class="token punctuation">;</span>
        <span class="token keyword">final</span> <span class="token keyword">boolean</span> dirtyOpaque <span class="token operator">=</span> <span class="token punctuation">(</span>privateFlags <span class="token operator">&amp;</span> PFLAG_DIRTY_MASK<span class="token punctuation">)</span> <span class="token operator">==</span> PFLAG_DIRTY_OPAQUE <span class="token operator">&amp;&amp;</span>
                <span class="token punctuation">(</span>mAttachInfo <span class="token operator">==</span> null <span class="token operator">||</span> <span class="token operator">!</span>mAttachInfo<span class="token punctuation">.</span>mIgnoreDirtyState<span class="token punctuation">)</span><span class="token punctuation">;</span>
        mPrivateFlags <span class="token operator">=</span> <span class="token punctuation">(</span>privateFlags <span class="token operator">&amp;</span> <span class="token operator">~</span>PFLAG_DIRTY_MASK<span class="token punctuation">)</span> <span class="token operator">|</span> PFLAG_DRAWN<span class="token punctuation">;</span>

        <span class="token comment" spellcheck="true">/*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
         *
         *      1. Draw the background
         *      2. If necessary, save the canvas' layers to prepare for fading
         *      3. Draw view's content
         *      4. Draw children
         *      5. If necessary, draw the fading edges and restore layers
         *      6. Draw decorations (scrollbars for instance)
         */</span>

        <span class="token comment" spellcheck="true">// Step 1, draw the background, if needed</span>
        <span class="token keyword">int</span> saveCount<span class="token punctuation">;</span>

        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>dirtyOpaque<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token function">drawBackground</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token comment" spellcheck="true">// skip step 2 &amp; 5 if possible (common case)</span>
        <span class="token keyword">final</span> <span class="token keyword">int</span> viewFlags <span class="token operator">=</span> mViewFlags<span class="token punctuation">;</span>
        <span class="token keyword">boolean</span> horizontalEdges <span class="token operator">=</span> <span class="token punctuation">(</span>viewFlags <span class="token operator">&amp;</span> FADING_EDGE_HORIZONTAL<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token keyword">boolean</span> verticalEdges <span class="token operator">=</span> <span class="token punctuation">(</span>viewFlags <span class="token operator">&amp;</span> FADING_EDGE_VERTICAL<span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token number">0</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>verticalEdges <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>horizontalEdges<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment" spellcheck="true">// Step 3, draw the content</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>dirtyOpaque<span class="token punctuation">)</span> <span class="token function">onDraw</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment" spellcheck="true">// Step 4, draw the children</span>
            <span class="token function">dispatchDraw</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token function">drawAutofilledHighlight</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment" spellcheck="true">// Overlay is part of the content and draws beneath Foreground</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>mOverlay <span class="token operator">!=</span> null <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>mOverlay<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                mOverlay<span class="token punctuation">.</span><span class="token function">getOverlayView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">dispatchDraw</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            <span class="token comment" spellcheck="true">// Step 6, draw decorations (foreground, scrollbars)</span>
            <span class="token function">onDrawForeground</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token comment" spellcheck="true">// Step 7, draw the default focus highlight</span>
            <span class="token function">drawDefaultFocusHighlight</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>

            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">debugDraw</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token function">debugDrawFocus</span><span class="token punctuation">(</span>canvas<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>

            <span class="token comment" spellcheck="true">// we're done...</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
</code></pre>
<p>通过注释可以看到，一般绘制过程分为7步，但第2步和第5步通常可以忽略，大概步骤：</p>
<p>Step 1. 绘制背景； Step 2. 忽略跳过； Step 3. <strong>绘制内容</strong>； Step 4. <strong>绘制子视图</strong>； Step 5. 忽略跳过； Step 6. 绘制装饰（前景，滚动条）; Step 7. 绘制默认焦点高光。</p>
<p>可以看到第三步onDraw()，也就是我们自定义View一般必须要重写的一个方法，该方法是空方法，因为每个子View的具体内容不一样，需要我们自己去实现逻辑。</p>
<p>第四步，即dispatchDraw(canvas):</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">// ----- View.java -----</span>
<span class="token comment" spellcheck="true">/**
  * Called by draw to draw the child views. This may be overridden
  * by derived classes to gain control just before its children are drawn
  * (but after its own view has been drawn).
  * @param canvas the canvas on which to draw the view
  */</span>
 <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">dispatchDraw</span><span class="token punctuation">(</span>Canvas canvas<span class="token punctuation">)</span> <span class="token punctuation">{</span>

 <span class="token punctuation">}</span></code></pre>
<p>可以看到View中的该方法是个空实现，但注释写的很清楚，如果该View包含子View的话，就要实现该方法，然后我们去ViewGroup的该方法中去看：</p>
<pre class=" language-java"><code class="language-java"><span class="token comment" spellcheck="true">// ------ViewGroup---------</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">dispatchDraw</span><span class="token punctuation">(</span>Canvas canvas<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> childrenCount<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">while</span> <span class="token punctuation">(</span>transientIndex <span class="token operator">>=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> mTransientIndices<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>transientIndex<span class="token punctuation">)</span> <span class="token operator">==</span> i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">final</span> View transientChild <span class="token operator">=</span> mTransientViews<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>transientIndex<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>transientChild<span class="token punctuation">.</span>mViewFlags <span class="token operator">&amp;</span> VISIBILITY_MASK<span class="token punctuation">)</span> <span class="token operator">==</span> VISIBLE <span class="token operator">||</span>
                    transientChild<span class="token punctuation">.</span><span class="token function">getAnimation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> null<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                more <span class="token operator">|=</span> <span class="token function">drawChild</span><span class="token punctuation">(</span>canvas<span class="token punctuation">,</span> transientChild<span class="token punctuation">,</span> drawingTime<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
            transientIndex<span class="token operator">++</span><span class="token punctuation">;</span>
            <span class="token keyword">if</span> <span class="token punctuation">(</span>transientIndex <span class="token operator">>=</span> transientCount<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                transientIndex <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span></code></pre>
<p>可以看到，在遍历其子View的时候，调用了绘制子View的方法，最终调用了子View的draw方法。同样的，如果该子 View 还有子视图，也会继续遍历下去调用 <code>drawChild()</code> 方法，继续绘制子 View，直到叶子 View 为止，这样不断递归下去，直到画完整棵 DecorView 树。</p>
<script>
        document.querySelectorAll('.github-emoji')
          .forEach(el => {
            if (!el.dataset.src) { return; }
            const img = document.createElement('img');
            img.style = 'display:none !important;';
            img.src = el.dataset.src;
            img.addEventListener('error', () => {
              img.remove();
              el.style.color = 'inherit';
              el.style.backgroundImage = 'none';
              el.style.background = 'none';
            });
            img.addEventListener('load', () => {
              img.remove();
            });
            document.body.appendChild(img);
          });
      </script>
            </div>
            <hr/>

            

    <div class="reprint" id="reprint-statement">
        
            <div class="reprint__author">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-user">
                        文章作者:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="/about" rel="external nofollow noreferrer">HuangLei</a>
                </span>
            </div>
            <div class="reprint__type">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-link">
                        文章链接:
                    </i>
                </span>
                <span class="reprint-info">
                    <a href="https://chuanpoxie.com/2020/08/24/Android-view%E7%9A%84%E7%BB%98%E5%88%B6%E6%B5%81%E7%A8%8B/">https://chuanpoxie.com/2020/08/24/Android-view%E7%9A%84%E7%BB%98%E5%88%B6%E6%B5%81%E7%A8%8B/</a>
                </span>
            </div>
            <div class="reprint__notice">
                <span class="reprint-meta" style="font-weight: bold;">
                    <i class="fas fa-copyright">
                        版权声明:
                    </i>
                </span>
                <span class="reprint-info">
                    本博客所有文章除特別声明外，均采用
                    <a href="https://creativecommons.org/licenses/by/4.0/deed.zh" rel="external nofollow noreferrer" target="_blank">CC BY 4.0</a>
                    许可协议。转载请注明来源
                    <a href="/about" target="_blank">HuangLei</a>
                    !
                </span>
            </div>
        
    </div>

    <script async defer>
      document.addEventListener("copy", function (e) {
        let toastHTML = '<span>复制成功，请遵循本文的转载规则</span><button class="btn-flat toast-action" onclick="navToReprintStatement()" style="font-size: smaller">查看</a>';
        M.toast({html: toastHTML})
      });

      function navToReprintStatement() {
        $("html, body").animate({scrollTop: $("#reprint-statement").offset().top - 80}, 800);
      }
    </script>



            <div class="tag_share" style="display: block;">
                <div class="post-meta__tag-list" style="display: inline-block;">
                    
                        <div class="article-tag">
                            
                                <a href="/tags/%E9%9D%A2%E8%AF%95/">
                                    <span class="chip bg-color">面试</span>
                                </a>
                            
                                <a href="/tags/Java/">
                                    <span class="chip bg-color">Java</span>
                                </a>
                            
                                <a href="/tags/Android/">
                                    <span class="chip bg-color">Android</span>
                                </a>
                            
                                <a href="/tags/2020/">
                                    <span class="chip bg-color">2020</span>
                                </a>
                            
                        </div>
                    
                </div>
                <div class="post_share" style="zoom: 80%; width: fit-content; display: inline-block; float: right; margin: -0.15rem 0;">
                    <link rel="stylesheet" type="text/css" href="/libs/share/css/share.min.css">
<div id="article-share">

    
    <div class="social-share" data-sites="twitter,facebook,google,qq,qzone,wechat,weibo,douban,linkedin" data-wechat-qrcode-helper="<p>微信扫一扫即可分享！</p>"></div>
    <script src="/libs/share/js/social-share.min.js"></script>
    

    

</div>

                </div>
            </div>
            
                <style>
    #reward {
        margin: 40px 0;
        text-align: center;
    }

    #reward .reward-link {
        font-size: 1.4rem;
        line-height: 38px;
    }

    #reward .btn-floating:hover {
        box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2), 0 5px 15px rgba(0, 0, 0, 0.2);
    }

    #rewardModal {
        width: 320px;
        height: 350px;
    }

    #rewardModal .reward-title {
        margin: 15px auto;
        padding-bottom: 5px;
    }

    #rewardModal .modal-content {
        padding: 10px;
    }

    #rewardModal .close {
        position: absolute;
        right: 15px;
        top: 15px;
        color: rgba(0, 0, 0, 0.5);
        font-size: 1.3rem;
        line-height: 20px;
        cursor: pointer;
    }

    #rewardModal .close:hover {
        color: #ef5350;
        transform: scale(1.3);
        -moz-transform:scale(1.3);
        -webkit-transform:scale(1.3);
        -o-transform:scale(1.3);
    }

    #rewardModal .reward-tabs {
        margin: 0 auto;
        width: 210px;
    }

    .reward-tabs .tabs {
        height: 38px;
        margin: 10px auto;
        padding-left: 0;
    }

    .reward-content ul {
        padding-left: 0 !important;
    }

    .reward-tabs .tabs .tab {
        height: 38px;
        line-height: 38px;
    }

    .reward-tabs .tab a {
        color: #fff;
        background-color: #ccc;
    }

    .reward-tabs .tab a:hover {
        background-color: #ccc;
        color: #fff;
    }

    .reward-tabs .wechat-tab .active {
        color: #fff !important;
        background-color: #22AB38 !important;
    }

    .reward-tabs .alipay-tab .active {
        color: #fff !important;
        background-color: #019FE8 !important;
    }

    .reward-tabs .reward-img {
        width: 210px;
        height: 210px;
    }
</style>

<div id="reward">
    <a href="#rewardModal" class="reward-link modal-trigger btn-floating btn-medium waves-effect waves-light red">赏</a>

    <!-- Modal Structure -->
    <div id="rewardModal" class="modal">
        <div class="modal-content">
            <a class="close modal-close"><i class="fas fa-times"></i></a>
            <h4 class="reward-title">你的赏识是我前进的动力</h4>
            <div class="reward-content">
                <div class="reward-tabs">
                    <ul class="tabs row">
                        <li class="tab col s6 alipay-tab waves-effect waves-light"><a href="#alipay">支付宝</a></li>
                        <li class="tab col s6 wechat-tab waves-effect waves-light"><a href="#wechat">微 信</a></li>
                    </ul>
                    <div id="alipay">
                        <img src="/medias/reward/alipay.png" class="reward-img" alt="支付宝打赏二维码">
                    </div>
                    <div id="wechat">
                        <img src="/medias/reward/wechat.png" class="reward-img" alt="微信打赏二维码">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
    $(function () {
        $('.tabs').tabs();
    });
</script>

            
        </div>
    </div>

    

    

    

    

    

    

    

<article id="prenext-posts" class="prev-next articles">
    <div class="row article-row">
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge left-badge text-color">
                <i class="fas fa-chevron-left"></i>&nbsp;上一篇</div>
            <div class="card">
                <a href="/2021/03/08/newtest/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/2.jpg" class="responsive-img" alt="newtest">
                        
                        <span class="card-title">newtest</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            hello

        document.querySelectorAll('.github-emoji')
          .forEach(el => {
            if (!el.dataset.src) { 
                        
                    </div>
                    <div class="publish-info">
                        <span class="publish-date">
                            <i class="far fa-clock fa-fw icon-date"></i>2021-03-08
                        </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-user fa-fw"></i>
                            Chuan Po Xie
                            
                        </span>
                    </div>
                </div>
                
            </div>
        </div>
        
        
        <div class="article col s12 m6" data-aos="fade-up">
            <div class="article-badge right-badge text-color">
                下一篇&nbsp;<i class="fas fa-chevron-right"></i>
            </div>
            <div class="card">
                <a href="/2020/07/05/%E9%9D%A2%E8%AF%95%E7%AE%80%E5%8D%95%E7%AE%97%E6%B3%95/">
                    <div class="card-image">
                        
                        
                        <img src="/medias/featureimages/7.jpg" class="responsive-img" alt="面试简单算法.md">
                        
                        <span class="card-title">面试简单算法.md</span>
                    </div>
                </a>
                <div class="card-content article-content">
                    <div class="summary block-with-text">
                        
                            Java算法
                        
                    </div>
                    <div class="publish-info">
                            <span class="publish-date">
                                <i class="far fa-clock fa-fw icon-date"></i>2020-07-05
                            </span>
                        <span class="publish-author">
                            
                            <i class="fas fa-bookmark fa-fw icon-category"></i>
                            
                            <a href="/categories/Java%E7%AE%97%E6%B3%95/" class="post-category">
                                    Java算法
                                </a>
                            
                            
                        </span>
                    </div>
                </div>
                
                <div class="card-action article-tags">
                    
                    <a href="/tags/Markdown/">
                        <span class="chip bg-color">Markdown</span>
                    </a>
                    
                    <a href="/tags/%E7%AE%97%E6%B3%95/">
                        <span class="chip bg-color">算法</span>
                    </a>
                    
                </div>
                
            </div>
        </div>
        
    </div>
</article>

</div>



<!-- 代码块功能依赖 -->
<script type="text/javascript" src="/libs/codeBlock/codeBlockFuction.js"></script>

<!-- 代码语言 -->

<script type="text/javascript" src="/libs/codeBlock/codeLang.js"></script>


<!-- 代码块复制 -->

<script type="text/javascript" src="/libs/codeBlock/codeCopy.js"></script>


<!-- 代码块收缩 -->

<script type="text/javascript" src="/libs/codeBlock/codeShrink.js"></script>


<!-- 代码块折行 -->

<style type="text/css">
code[class*="language-"], pre[class*="language-"] { white-space: pre !important; }
</style>


    

</main>




    <footer class="page-footer bg-color">
    
        <link rel="stylesheet" href="/libs/aplayer/APlayer.min.css">
<style>
    .aplayer .aplayer-lrc p {
        
        display: none;
        
        font-size: 12px;
        font-weight: 700;
        line-height: 16px !important;
    }

    .aplayer .aplayer-lrc p.aplayer-lrc-current {
        
        display: none;
        
        font-size: 15px;
        color: #42b983;
    }

    
    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body {
        left: -66px !important;
    }

    .aplayer.aplayer-fixed.aplayer-narrow .aplayer-body:hover {
        left: 0px !important;
    }

    
</style>
<div class="">
    
    <div class="row">
        <meting-js class="col l8 offset-l2 m10 offset-m1 s12"
                   server="netease"
                   type="playlist"
                   id="503838841"
                   fixed='true'
                   autoplay='false'
                   theme='#42b983'
                   loop='all'
                   order='random'
                   preload='auto'
                   volume='0.7'
                   list-folded='true'
        >
        </meting-js>
    </div>
</div>

<script src="/libs/aplayer/APlayer.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>

    
    <div class="container row center-align" style="margin-bottom: 0px !important;">
        <div class="col s12 m8 l8 copy-right">
            Copyright&nbsp;&copy;
            <span id="year">2020</span>
            <a href="/about" target="_blank">Chuan Po Xie</a>
            |&nbsp;Powered by&nbsp;<a href="https://hexo.io/" target="_blank">Hexo</a>
            |&nbsp;Theme&nbsp;<a href="https://github.com/blinkfox/hexo-theme-matery" target="_blank">Matery</a>
            <br>
            
            
            
            
            
            
            <span id="busuanzi_container_site_pv">
                |&nbsp;<i class="far fa-eye"></i>&nbsp;总访问量:&nbsp;<span id="busuanzi_value_site_pv"
                    class="white-color"></span>&nbsp;次
            </span>
            
            
            <span id="busuanzi_container_site_uv">
                |&nbsp;<i class="fas fa-users"></i>&nbsp;总访问人数:&nbsp;<span id="busuanzi_value_site_uv"
                    class="white-color"></span>&nbsp;人
            </span>
            
            <br>
            
            <br>
            
        </div>
        <div class="col s12 m4 l4 social-link social-statis">
    <a href="https://github.com/chuanpoxie/chuanpoxie.github.io" class="tooltipped" target="_blank" data-tooltip="访问我的GitHub" data-position="top" data-delay="50">
        <i class="fab fa-github"></i>
    </a>



    <a href="mailto:just_test@live.cn" class="tooltipped" target="_blank" data-tooltip="邮件联系我" data-position="top" data-delay="50">
        <i class="fas fa-envelope-open"></i>
    </a>







    <a href="tencent://AddContact/?fromId=50&fromSubId=1&subcmd=all&uin=642419907" class="tooltipped" target="_blank" data-tooltip="QQ联系我: 642419907" data-position="top" data-delay="50">
        <i class="fab fa-qq"></i>
    </a>







    <a href="/atom.xml" class="tooltipped" target="_blank" data-tooltip="RSS 订阅" data-position="top" data-delay="50">
        <i class="fas fa-rss"></i>
    </a>

</div>
    </div>
</footer>

<div class="progress-bar"></div>


    <!-- 搜索遮罩框 -->
<div id="searchModal" class="modal">
    <div class="modal-content">
        <div class="search-header">
            <span class="title"><i class="fas fa-search"></i>&nbsp;&nbsp;搜索</span>
            <input type="search" id="searchInput" name="s" placeholder="请输入搜索的关键字"
                   class="search-input">
        </div>
        <div id="searchResult"></div>
    </div>
</div>

<script src="/js/search.js"></script>
<script type="text/javascript">
$(function () {
    searchFunc("/search.xml", 'searchInput', 'searchResult');
});
</script>

    <!-- 回到顶部按钮 -->
<div id="backTop" class="top-scroll">
    <a class="btn-floating btn-large waves-effect waves-light" href="#!">
        <i class="fas fa-arrow-up"></i>
    </a>
</div>


    <script src="/libs/materialize/materialize.min.js"></script>
    <script src="/libs/masonry/masonry.pkgd.min.js"></script>
    <script src="/libs/aos/aos.js"></script>
    <script src="/libs/scrollprogress/scrollProgress.min.js"></script>
    <script src="/libs/lightGallery/js/lightgallery-all.min.js"></script>
    <script src="/js/matery.js"></script>

    <!-- Baidu Analytics -->

    <!-- Baidu Push -->

<script>
    (function () {
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        } else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
</script>

    
    
    <script async src="/libs/others/busuanzi.pure.mini.js"></script>
    

    

    

    

    

    
    <script type="text/javascript" src="/libs/background/ribbon-dynamic.js" async="async"></script>
    

    
    <script src="/libs/instantpage/instantpage.js" type="module"></script>
    

</body>

</html>
